package com.mjk.common.tools.task.multitask;

import com.mjk.common.base.error.BeeError;
import com.mjk.common.base.response.BeeResponse;
import com.mjk.common.tools.task.ITask;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 基于 CompletableFuture 的 异步任务执行器
 *
 * 可用于 串行任务 转 并行任务
 */
public class MultiAnsyTaskExecute {
    private final List<ITask> tasks;
    /**
     * 创建异步任务执行的线程池
     */
    private ExecutorService pool = Executors.newFixedThreadPool(100, new CustomizableThreadFactory("CompletableTaskExecute"));


    public MultiAnsyTaskExecute(List<ITask> tasks) {
        this.tasks = tasks;
    }

    /**
     * 异步执行 返回结果
     *
     * @return
     */
    public BeeResponse supplyAsync() {
        List<CompletableFuture<BeeResponse>> futures = new ArrayList<>();
        if (CollectionUtils.isEmpty(tasks)) {
            return BeeError.BEE_SUC.tranceError();
        }
        tasks.forEach(item -> {
            futures.add(CompletableFuture.supplyAsync(() -> {
                return item.doTask();
            }));
        });
        CompletableFuture<Void> allTask = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
        AtomicReference<BeeResponse> result = new AtomicReference<>(BeeError.BEE_SUC.tranceError());
        allTask.thenAccept(v -> {
            futures.forEach(item -> {
                BeeResponse rsp = item.join();
                if (!rsp.getCode().equals(BeeError.BEE_SUC.getCode())) {
                    result.set(rsp);
                }
            });
        }).join();
        return result.get();
    }

    /**
     * 异步执行，不返回结果
     */
    public void runAsync() {
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        if (CollectionUtils.isEmpty(tasks)) {
            return;
        }
        tasks.forEach(item -> {
            CompletableFuture<Void> testi = CompletableFuture.runAsync(() -> {
                item.doTask();
            });
            futures.add(testi);
        });
        CompletableFuture<Void> allTask = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
        allTask.join();
    }
}
